// This is the View
// Its only job is to display what the user sees
// It performs no calculations, but instead passes
// information entered by the user to whomever needs
// it.

package pt.iscte.dcti.pa.view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;
import java.util.Observable;
import java.util.Observer;

import javax.swing.*;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

import utils.Common;
import utils.RmiWrapper_deprecated;
import utils.SingletonRmiWrapper;
import controller.WorksheetController_dep;

public class WorksheetView extends JFrame {

	private DynamicTable dynamicTable;

	private Display display;
	private final Shell shell;

	private VisibleElement[][] matriz;
	
	private int[] lockedCell;
	
	private org.eclipse.swt.graphics.Color lockedCellColour;
	
	//GETTERS & SETTERS: start
	public int[] getLockedCell() {
		return lockedCell;
	}

	public void setLockedCell(int abscissa, int ordinate) {
		
		if (this.lockedCell == null) {
			this.lockedCell = new int[2];
		}
		
		this.lockedCell[0] = abscissa;
		this.lockedCell[1] = ordinate;
	}
	//GETTERS & SETTERS: end

	public WorksheetView(int _numRows, int _numColumns) {

		// ctrl = new Control();
		display = new Display();
		shell = new Shell(display);
		shell.setLayout(new RowLayout(SWT.HORIZONTAL));

		dynamicTable = new DynamicTable(shell);

		setMatriz(_numRows, _numColumns);

		dynamicTable.load(matriz);

		setTableEditor(dynamicTable.getTable());
		
		this.lockedCell = null;
		this.lockedCellColour = null;

	}

	public boolean setCellText(final int abscisa, final int ordinate,
			final String value) {

		try {
			display.syncExec(new Runnable() {

				@Override
				public void run() {
					dynamicTable.getTable().getItem(abscisa).setText(ordinate, value);
				}
			});

			return true;
		} catch (Exception e) {
			System.out.println(e.getMessage());
			return false;
		}
	}

	public boolean lockCell(final int abscisa, final int ordinate) {
	
			if (this.getLockedCell() != null) {
				final int lockedCellAbscissa = this.getLockedCell()[0];
				final int lockedCellOrdinate = this.getLockedCell()[1];
				
				
				
				display.syncExec(new Runnable() {

					@Override
					public void run() {
						final TableItem item = dynamicTable.getTable().getItem(lockedCellAbscissa);
						item.setBackground(lockedCellOrdinate, lockedCellColour);					
					}
				});
			}
			
			this.setLockedCell(abscisa, ordinate);
			
			display.syncExec(new Runnable() {

				@Override
				public void run() {					
					final TableItem item = dynamicTable.getTable().getItem(abscisa);
					lockedCellColour = item.getBackground(ordinate);
					item.setBackground(ordinate, display.getSystemColor(SWT.COLOR_YELLOW));					
				}
			});
		
			return true;
	
	}

	public VisibleElement[][] getMatriz() {
		return this.matriz;
	}

	public void addObserver(java.util.Observer theObserver) {
		for (VisibleElement[] linha : matriz) {
			for (VisibleElement visibleElement : linha) {
				visibleElement.addObserver(theObserver);
			}
		}
	}

	public void showTable() {

		shell.pack();
		shell.open();

		if (shell != null && display != null) {
			while (!shell.isDisposed()) {
				if (!display.readAndDispatch())
					display.sleep();
			}
			display.dispose();
		}

		inspectSheet();
	}

	public void addListener(final Table table, final TableEditor editor) {

		table.addListener(SWT.MouseDown, new Listener() { // para o evento
					// MouseDown

					public void handleEvent(Event event) {
						Rectangle clientArea = table.getClientArea();
						Point pt = new Point(event.x, event.y);

						int index = table.getTopIndex();
						while (index < table.getItemCount()) { // para cada
																// linha
							boolean visible = false;
							final TableItem item = table.getItem(index);

							for (int i = 0; i < table.getColumnCount(); i++) { // para cada célula de cada linha

								Rectangle rect = item.getBounds(i);
								if (rect.contains(pt)) {
									final int column = i;
									final Text textBox = new Text(table, SWT.NONE); // para a textbox

									Listener textListener = getListener(item, index, column, textBox);

									textBox.addListener(SWT.FocusIn, textListener);
									textBox.addListener(SWT.FocusOut, textListener);
									// textBox.addListener(SWT.Traverse,
									// textListener);

									editor.setEditor(textBox, item, i);
									textBox.setText(item.getText(i));

									textBox.selectAll();
									textBox.setFocus();
									return;
								}
								if (!visible && rect.intersects(clientArea)) {
									visible = true;
								}
							}
							if (!visible)
								return;
							index++;
						}
					}
				});
	}

	private void setTableEditor(Table table) {
		final TableEditor editor = new TableEditor(table);
		editor.horizontalAlignment = SWT.LEFT;
		editor.grabHorizontal = true;

		addListener(table, editor);
	}

	private void setMatriz(int numRows, int numColumns) {
		matriz = new VisibleElement[numRows][numColumns];

		for (int i = 0; i < numRows; i++) {
			for (int j = 0; j < numColumns; j++) {
				matriz[i][j] = new VisibleElement(i, j, this);
			}
		}
	}

	// cada célula leva um listener
	private Listener getListener(final TableItem item, final int itemIndex,
			final int columnIndex, final Text textBox) {
		return new Listener() {
			public void handleEvent(final Event e) {

				switch (e.type) {
				case SWT.FocusIn: {
					// getFormula(itemIndex, columnIndex);
					// TODO avisa servidor
					SingletonRmiWrapper wrapper = SingletonRmiWrapper .getWrapper();
					boolean success = wrapper.lockCell(itemIndex, columnIndex);

					if (success) {
						System.out .println(String.format("Cell [%s,%s] LOCKED!", itemIndex, columnIndex));
					} else {
						System.out.println("The lock has failed!");
					}
					break;
				}
				case SWT.FocusOut:
					setValue(item, itemIndex, columnIndex, textBox);
					textBox.dispose();
					break;
				case SWT.Traverse:
					switch (e.detail) {
					case SWT.TRAVERSE_TAB_NEXT:
					case SWT.TRAVERSE_RETURN:
						setValue(item, itemIndex, columnIndex, textBox);
						// FALL THROUGH
					case SWT.TRAVERSE_ESCAPE:
						textBox.dispose();
						e.doit = false;
					}
					break;
				}
			}
		};
	}

	/*
	 * private void getFormula(int abscissa, int ordinate) {
	 * matriz[abscissa][ordinate].fireObserver(); }
	 */
	private void setValue(final TableItem item, int rowItemIndex, final int columnIndex, final Text textBox) {

		String textValue = textBox.getText();
		item.setText(columnIndex, textValue);

		if (textValue != null && !textValue.isEmpty()) {
			matriz[rowItemIndex][columnIndex].setValue(textValue);
		}
	}

	// imprime a folha de calculo
	private void inspectSheet() {
		for (VisibleElement[] linha : matriz) {
			for (VisibleElement celula : linha) {
				System.out.println((celula != null ? celula.getValue() : " ")
						+ "|");
			}
			System.out.println();
		}
	}
}
